"use strict";
define(function(){
	var Component = function(componentId, parentCtl, struct) {
		this.componentId = componentId;
		this.id = parentCtl.id;
		this.instance = parentCtl.instance;
		this.project = this.instance.project;
		this.struct = struct;
		this.shell = parentCtl;
		this.container = parentCtl.box.empty();
		if (struct.version === 'DYN2')
			this.extendProps = parentCtl.profile.props ? (parentCtl.profile.props.extend || {}) : {};
		else
			this.extendProps = parentCtl.custProp;
		this.attributes = parentCtl.attributes;
		this.methods = {};
		
		var runtime = parentCtl.runtime, local = this.instance.initVars(struct);

		// 工单自定义属性里定会了这个woTabc的话，则直接替换组件配置的tabc
		if (this.extendProps.tabc && this.instance.options && this.instance.options.woTabc) {
			this.extendProps.tabc = this.instance.options.woTabc;
		}
		if (local.tabc && this.extendProps.tabc) {
			var tabc = this.extendProps.tabc.toLowerCase();
			if (this.instance.data[tabc]) {
				for(var key in local.tabc) {
					if (this.instance.data[tabc][key] === undefined)
						this.instance.data[tabc][key] = local.tabc[key];
				}
				local.tabc = this.instance.data[tabc];
			} else {
				// console.error('主结构中无此tabc表对象:' + tabc)
				this.instance.data[tabc] = local.tabc;
			}
		}
		struct.tbList = struct.tbList || [];
		if (struct.version === 'DYN2')
			extendProps(this.instance.runtime, struct, true);
		else
			extendProps(this.instance.runtime, struct);
		
		// create internal runtime object
		this.runtime = {
			id : this.id,
			project : this.project,
			instance : this.instance,
			struct : struct,
			afterDraw: [],
			props : {
				pub : this.instance.runtime.props.pub,
				local: (struct.version === 'DYN2' ? struct.props.local : struct.LocList)
			},
			data : {
				pub : this.instance.data,
				local : local
			},
			// 页面流转步骤
			flows : [],
			// 绘制容器
			container : this.container,
			// 控件表
			ctls : {},
			// 变量监听器
			binder : {},
			sqlQueue : {},
			children : {},
			parent : runtime,
			namespace : runtime.namespace + '.' + this.id,
			component : this,
			extendProps : this.extendProps
		};
		runtime.children[this.runtime.id] = this.runtime;
		parentCtl.component = this;
		this.container.attr('data-com', struct.id)
		// $F.log('Component', '组件加载完毕：' + this.id, this.runtime);
	};
	
	Component.prototype = {
		init : function() {
			var a = this;
			// 使用了系统组件框架
			// console.log(a.extendProps)
			if (a.extendProps.shell == 1) {
				var component_head = $('<div class="dyn_component_head alone" />').appendTo(a.container),
					component_title = $('<div class="titlebar abbr"><span class="icon"></span><span class="title"></span><span class="digest"></span></div>').appendTo(component_head),
					component_btns = $('<div class="btnsbar" />').appendTo(component_head),
					showtype = a.extendProps.showtype || 0, 
					savecmd,
					maxcmd,
					mincmd,
					component_save,
					component_minimal,
					component_maximal;
				var paddingStyles = a.container.css('padding');
				a.container = a.shell.box = a.runtime.container = $('<div class="dyn_component_body" />').appendTo(a.container.css('padding', '0'));
				a.container.css('padding', paddingStyles);
				
				if (a.struct.version === 'DYN2') {
					savecmd = a.extendProps.savecmd || '';
					maxcmd = a.extendProps.maxcmd || (a.struct.cmds.internal['win.max'] ? 'win.max' : '');
					mincmd = a.extendProps.mincmd || (a.struct.cmds.internal['win.min'] ? 'win.min' : '');
				} else {
					savecmd = a.extendProps.savecmd;
					savecmd = savecmd ? ('P' + savecmd) : '';
					maxcmd = a.extendProps.maxcmd;
					maxcmd = maxcmd ? ('P' + maxcmd) : '';
					mincmd = a.extendProps.mincmd;
					mincmd = mincmd ? ('P' + mincmd) : '';
				}
				if (savecmd && savecmd !== '') {
					component_save = $('<a href="javascript:;" class="save" title="保存"><i class="far fa-save"></i></a>')
						.appendTo(component_btns)
						.on('click', function(e){
							e.preventDefault();
							a.doCmd(savecmd, {CTRL: a});
						});
				}
				var oldtype = 0;
				component_maximal = $('<a href="javascript:;" class="maximal" title=""><i class="far ' + (showtype == 2 ? 'fa-arrow-circle-down':(showtype==0 ? 'fa-angle-double-down':'fa-angle-double-up')) + '"></i></a>')
					.appendTo(component_btns)
					.attr('title', (showtype == 2? '展开' : (showtype == 1 ? '简要' : '详情')))
					.on('click', function(e, R){
						e.preventDefault();
						component_title.find('.digest').hide();
						a.container.show();
						if (showtype == 2)
							showtype = oldtype;
						else
							showtype = (showtype !== 1 ? 1 : 0);
						if (maxcmd && maxcmd !== '') {
							// 允许最大化
							component_maximal.find('i')
								.removeClass('fa-arrow-circle-down')
								.toggleClass('fa-angle-double-down', showtype!==1)
								.toggleClass('fa-angle-double-up', showtype==1);
							component_maximal.attr('title', (showtype == 1 ? '简要' : '详情'))
						} else {
							component_maximal.hide();
						}
						if (mincmd && mincmd !== '')
							component_minimal.show();
						if (component_save)
							component_save.show();
						if (maxcmd && maxcmd !== '') {
							var EVENT = {
								SHOWTYPE: showtype
							}
							if (R) {
								if ($.type(R.EVENT) === 'string')
									EVENT = R.EVENT;
								else
									EVENT = $.extend(EVENT, R.EVENT);
							}
							a.doCmd(maxcmd, {
								CTRL: a, 
								EVENT: EVENT
							});
						}
					});
				component_minimal = $('<a href="javascript:;" class="minimal" title="最小化"><i class="far fa-minus"></i></a>')
					.appendTo(component_btns)
					.on('click', function(e, R){
						e.preventDefault();
						component_minimal.hide();
						if (component_save)
							component_save.hide();
						component_maximal.show().find('i')
							.removeClass('fa-angle-double-down fa-angle-double-up')
							.addClass('fa-arrow-circle-down');
						component_maximal.attr('title', '展开');
						
						oldtype = showtype;
						showtype = 2;
						component_title.find('.digest').show();
						a.container.hide();
						if (mincmd && mincmd !== '') {
							var EVENT = {
								SHOWTYPE: showtype
							}
							if (R) {
								if ($.type(R.EVENT) === 'string')
									EVENT = R.EVENT;
								else
									EVENT = $.extend(EVENT, R.EVENT);
							}
							a.doCmd(mincmd, {
								CTRL: a, 
								EVENT: EVENT
							}, true);
						}
					});
				
				if (showtype == 2) {
					component_minimal.hide();
					component_title.find('.digest').show();
					a.container.hide();
				} else {
					if (!maxcmd || maxcmd === '')
						component_maximal.hide();
					if (!mincmd || mincmd === '')
						component_minimal.hide();
				}
				
				$('.title', component_title).text(a.extendProps.title || '');
				$('.icon', component_title).html(CtlUtils.parseIcon(a.extendProps.icon));
				var bp = function(propertyName, el) {
					if (a.instance.getProperty(propertyName, a.runtime)) {
						el.text(a.instance.getValue(propertyName, a.runtime, ''));
						a.instance.bindValue(propertyName, {
							type: 'INTERNAL',
							id: a.id,
							runtime: a.runtime
						}, function(e){
							el.text(e.data);
						})
					}
				}
				bp('var._title', $('.title', component_title));
				bp('var._digest', $('.digest', component_title));
				bp('var._cp_title', $('.title', component_title));
				bp('var._cp_digest', $('.digest', component_title));
				a.runtime.extra = component_head;
			} else {
				a.runtime.extra = a.shell.head;
			}
			
			// 给文件进行relationId赋值
			if (a.instance.oId)
				a.runtime.relationId = a.instance.oId;
			else
				a.runtime.relationId = a.instance.customer.getValue("customer_guid");

			// 为了兼容旧版本(U版本)，在未定义extendProps.tabc时，不再读取tabc数据
			if (a.struct.version === 'DYN2' || a.extendProps.tabc)
				a.loadTabc();
			
			a.instance.initCmd(a.runtime);
			
			$D.startStep(a.runtime);
			a.shell.ctls = a.runtime.container.data('controls');
			a.instance.afterRender(a.runtime);
		},
		
		winMin : function(R) {
			var a = this;
			$('a.minimal', a.runtime.extra).trigger('click', R);
		},
		
		winMax : function(R) {
			var a = this;
			$('a.maximal', a.runtime.extra).trigger('click', R);
		},
		
		beforeSave : function() {
			if (this.struct.version == 'DYN2')
				return this.doCmd('save.before', {}, true);
			else
				return this.doCmd('P-10');
		},
		
		save : function(passively) {
			if (this.runtime.struct.Que) {
				// console.log('执行问卷组件保存方法：' + this.id + '@' + this.struct.id)
				this.saveTabc(passively);
			}
			if (this.struct.version == 'DYN2')
				return this.doCmd('save', {}, true);
			else
				return this.doCmd('P-70');
		},
		
		afterSave : function() {
			if (this.struct.version === 'DYN2')
				return this.doCmd('save.after', {}, true);
			else
				return this.doCmd('P1');
		},
		
		/**
		 * 组件加载数据
		 */
		loadTabc : function() {
			const runtime = this.runtime, struct = this.struct, instance = this.instance, tbList = struct.tbList;
			
			// 私有化tabc时，需要组件自行读取tabc数据
			// console.debug(this.extendProps)
			if (this.extendProps.tabc) {
				if (! runtime.relationId)
					$F.err('Dyn - draw', '组件[' + this.runtime.struct.id + ']未指定业务关联ID');
				else {
					if (!tbList.includes(this.extendProps.tabc.toLowerCase()))
						tbList.push(this.extendProps.tabc.toLowerCase());
					console.debug('load private tabc data: ', tbList);
				}
			}
			if (tbList.length === 0)
				return;
				
			// 将所有tabc的变量定义放入到全局变量定义中
			for(var key in runtime.props.local) {
				var prop = runtime.props.local[key];
				if (prop.ns === 'tabc') {
					$.each(tbList, function(i, tabc) {
						if (! runtime.props.pub[tabc + '.' + prop.field]) {
							runtime.props.pub[tabc + '.' + prop.field] = {
								ns: tabc,
								field: prop.field,
								t: prop.t
							};
						}
					})
				}
			}
			
			$F.dataService("JSGenerateServlet2", {
				title: '加载组件数据',
				data: {
					token: runtime.project.token,
					dbPool: instance.dbPool,
					name: "Dyn.ZJ.Data.Load",
					keyId: runtime.relationId,
					dyn: tbList,
					cpFakeId: struct.id
				},
				digest: runtime.project.digest,
				async: false,
				success: function(data) {
					// console.log(data);
					if (data.code > 0) {
						$F.log('[Component - loadTabc]', '载入TABC数据', data.value.data);
						var prop;
						$.each(data.value.data, function(i, v) {
							v.tableName = v.tableName.toLowerCase();
							v.fieldName = v.fieldName.toLowerCase();
							// 在公共变量中创建对应的tabc队列
							if (! runtime.data.pub[v.tableName])
								runtime.data.pub[v.tableName] = {};
							prop = runtime.instance.getProperty(v.tableName + '.' + v.fieldName, runtime);
							if (prop && (struct.version === 'DYN2' ? prop.VT == 2 : prop.t == 2)) {
								if ($F.parseDate(v.value).getFullYear() === 1900)
									runtime.data.pub[v.tableName][v.fieldName] = '';
								else
									runtime.data.pub[v.tableName][v.fieldName] = v.value;
							} else
								runtime.data.pub[v.tableName][v.fieldName] = v.value;
						})
						$F.log('[Component - loadTabc]', '载入流转数据', data.value.flow);
						var flows = [], curPage = runtime.page;
						$.each(data.value.flow, function(i, flow) {
							// console.log('load sub page: ' + flow);
							curPage = $D.getPage(runtime, flow);
							if (curPage) {
								flows.push({
									id: curPage.id,
									name: curPage.name
								})
							} else {
								$F.err('[Component - loadTabc]', '加载子页面结构失败 - ' + flow);
							}
						})
						runtime.page = curPage;
						runtime.flows = flows;
					} else
						$F.err('Component - loadTabc', data.message);
				}
			});
		},
		
		saveTabc : function(passively) {
			var runtime = this.runtime, struct = this.struct, tbList = struct.tbList || [], tabcData = {}, flows = [];
			
			var a = this;
			if (passively) {
				a.beforeSave();
				$.each(tbList, function(i, tb) {
					if (runtime.data.pub[tb])
						tabcData[tb] = runtime.data.pub[tb];
				});
				if (a.extendProps.tabc) {
					tabcData[a.extendProps.tabc.toLowerCase()] = runtime.data.pub[a.extendProps.tabc];
					tbList.push(a.extendProps.tabc);
				}
				//console.log('保存TABC数据：', tabcData);
			}
			if (runtime.flows.length > 1) {
				$.each(runtime.flows, function(i, flow) {
					flows.push(flow.id)
				})
			}
			//console.log('保存流转数据：', flows);
			$F.dataService("JSGenerateServlet2", {
				data: {
					token: runtime.project.token,
					dbPool: a.instance.dbPool,
					name: "Dyn.ZJ.Data.Save",
					keyId: runtime.relationId,
					mFakeId: runtime.instance.dynId,
					cpFakeId: struct.GroupIdA,
					dyn: (passively ? tbList : []),
					data: (passively ? tabcData : {}),
					flow: flows
				},
				digest: runtime.project.digest,
				success: function(data) {
					if (data.code < 0)
						$F.err('Components - saveTabc', data.message);
				},
				always: function() {
					if (passively)
						a.afterSave();
				}
			});
		},
		
		/**
		 * 执行组件的命令组
		 * @param cmdId {string} 命令组号
		 * @param ev {any} 入参，JSON对象
		 * @param [internal] {boolean} 执行内部命令
		 */
		doCmd : function(cmdId, ev, internal) {
			this.instance.doCmd(cmdId, ev, this.runtime, '', internal);
		},
		
		onCustomerChange : function(){
			if (this.struct.version == 'DYN2')
				this.doCmd('custom.change', {}, true);
			else
				this.doCmd('P5');
		},
		
		onActive : function() {
			if (this.struct.version == 'DYN2')
				this.doCmd('active', {}, true);
			else
				this.doCmd('P-99');
		},
		
		fireBindProperty : function(e) {
			this.shell.fireBindProperty(e);
		},
		
		attr : function(key, value) {
			if (value == undefined)
				return this.attributes[key];
			else
				this.attributes[key] = value;
		},
		
		destroy : function() {
			if (this.runtime) {
				$F.log('Component - destroy', 'Destroy component: ' + this.runtime.namespace);
				this.instance.destroyCtls(this.runtime.ctls);
				this.container = null;
				this.shell = null;
				this.runtime.component = null;
				this.runtime = null;
				this.instance = null;
				this.project = null;
				this.struct = null;
			}
		}
	}
	
	function extendProps(runtime, struct, DYN2) {
		var src;
		if (DYN2)
			src = struct.props.pub;
		else
			src = struct.VarList;
		for (var key in src) {
			if (src.hasOwnProperty(key)) {
				var property = src[key];
				if (! runtime.props.pub[key]) {
					runtime.props.pub[key] = property;
					if (DYN2) {
						if (! runtime.data.pub[property.ns]) {
							runtime.data.pub[property.ns] = {};
							if (property.ns !== 'temp') {
								// tabc数据，且在当前主页面中未引用申明，需要重新读入
								struct.tbList.push(property.ns);
							}
 						}
						if (runtime.data.pub[property.ns][property.field] === undefined)
							runtime.data.pub[property.ns][property.field] = runtime.instance.getDefaultValue(property.t, property.v);
						
						if (property.ns === 'temp') {
							var instance = runtime.instance;
							if (property.field.startWith('cust_')) {
								// 绑定到Customer对象
								instance.bindCustomerProperties[key] = property.field.substring(5);
								// console.log('监听Customer：' + a.bindCustomerProperties[key]);
								if (instance.customer) {
									instance.data[property.ns] = instance.data[property.ns] || {};
									instance.data[property.ns][property.field] = instance.customer.getValue(instance.bindCustomerProperties[key]);
									runtime.data.pub[property.ns][property.field] = instance.customer.getValue(instance.bindCustomerProperties[key]);
								}
							} else if (property.field.startWith('obj_')) {
								// 绑定到Objective对象
								instance.bindObjectiveProperties[key] = property.field.substring(4);
								// console.log('监听Objective：' + a.bindObjectiveProperties[key]);
								// 初始化该值
								if (instance.objective) {
									instance.data[property.ns] = instance.data[property.ns] || {};
									instance.data[property.ns][property.field] = instance.objective.getValue(instance.bindObjectiveProperties[key]);
									runtime.data.pub[property.ns][property.field] = instance.objective.getValue(instance.bindObjectiveProperties[key]);
								}
							}
						}
					} else {
						runtime.data.pub[property.pM] = runtime.data.pub[property.pM] || {};
						runtime.data.pub[property.pM][property.pS] = runtime.instance.getDefaultValue(property.VT, property.DV);
					}
				}
			}
		}
		runtime.instance.bindCustomer();
	}
	
	return {
		create : function(componentId, parentCtl, struct) {
			return new Component(componentId, parentCtl, struct);
		}
	}
})
